package com.youku.component.procedure;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.youku.component.CaseStep;
import com.youku.component.TestCase;
import com.youku.component.result.HttpExecuteResult;
import com.youku.expression.Expression;
import com.youku.expression.Position;
import com.youku.util.Consts;
import com.youku.util.HttpHelper;

public class HttpProcedure extends AbstractProcedure {

	private static final Logger logger = LoggerFactory.getLogger(HttpProcedure.class);

	private Expression url;

	private Expression body;

	private Map<String, Expression> arguments = new HashMap<>();

	private Map<String, Expression> heads = new HashMap<>();

	private Map<String, Expression> cookies = new HashMap<>();

	private int retryTime = 0;// 重试次数

	public HttpProcedure(String id, TestCase testCase, String times) {
		super(id, testCase, times);
	}

	public HttpProcedure() {
		super();
	}

	public int getRetryTime() {
		return retryTime;
	}

	public void retry() {
		retryTime++;
	}

	public void setRetryTime(int retryTime) {
		this.retryTime = retryTime;
	}

	public void addArgument(String key, String valueString) {
		arguments.put(key, createExpression(valueString));
	}

	public String getArgument(String key) {
		Expression exp = arguments.get(key);
		if (exp == null)
			return null;
		return exp.get();
	}

	public void addHead(String key, String valueString) {
		heads.put(key, createExpression(valueString));
	}

	public String getHead(String key) {
		Expression exp = heads.get(key);
		if (exp == null)
			return null;
		return exp.get();
	}

	public void addCookie(String key, String valueString) {
		cookies.put(key, createExpression(valueString));
	}

	public String getCookie(String key, String value) {
		Expression exp = cookies.get(key);
		if (exp == null)
			return null;
		return exp.get();
	}

	public String getUrl() {
		if (url == null)
			throw new RuntimeException("缺少url");
		return url.get();
	}

	public void setUrl(String valueString) {
		this.url = createExpression(valueString);
	}

	public String getBody() {
		if (body == null)
			return null;
		return body.get();
	}

	public void setBody(String valueString) {
		this.body = createExpression(valueString);
	}

	@SuppressWarnings("unchecked")
	@Override
	public void invoke() {
		Map<String, Object> resultMap = HttpHelper.post(initParamMap());

		HttpExecuteResult result = new HttpExecuteResult();
		result.setResponseBody((String) resultMap.get(Consts.BODY));
		result.setResponseCookies((Map<String, String>) resultMap.get(Consts.COOKIE));
		result.setResponseStatus(resultMap.get(Consts.STATUS).toString());

		results.add(result);
	}

	private Map<String, Object> initParamMap() {
		Map<String, Object> params = new HashMap<>();
		String url = getUrl();
		String body = getBody();
		Map<String, String> argMap = generate(arguments);
		Map<String, String> headMap = generate(heads);
		Map<String, String> cookieMap = generate(heads);
		params.put(Consts.BODY, body);
		params.put(Consts.URL, url);
		params.put(Consts.PARAM, argMap);
		params.put(Consts.HEAD, headMap);
		params.put(Consts.COOKIE, cookieMap);
		logger.debug("---------------------完成参数的拼装");
		logger.debug("请求url:{}", url);
		logger.debug("请求体:{}", body);
		logger.debug("请求参数:{}", argMap.toString());
		logger.debug("请求头:{}", headMap.toString());
		logger.debug("请求cookie:{}", cookieMap.toString());
		return params;
	}

	private Map<String, String> generate(Map<String, Expression> map) {
		Map<String, String> args = null;
		for (Entry<String, Expression> entry : map.entrySet()) {
			if (args == null) {
				args = new HashMap<>();
			}
			args.put(entry.getKey(), entry.getValue().get());
		}

		if (args == null)
			args = Collections.emptyMap();

		return args;
	}

	@Override
	public void updatePosition(Position position) {
		super.updatePosition(position);
		if (url != null)
			url.setPosition(position);
		if (body != null)
			body.setPosition(position);

		if (arguments.size() > 0) {
			arguments = updatePosition(arguments, position);
		}

		if (heads.size() > 0) {
			heads = updatePosition(heads, position);
		}

		if (cookies.size() > 0) {
			cookies = updatePosition(cookies, position);
		}

	}

	private Map<String, Expression> updatePosition(Map<String, Expression> arguments, Position position) {
		Map<String, Expression> map = new HashMap<>();
		for (Entry<String, Expression> entry : arguments.entrySet()) {
			Expression exp = entry.getValue();
			exp.setPosition(position);
			map.put(entry.getKey(), exp);
		}
		return map;
	}

	@Override
	public CaseStep cloneStep() {
		HttpProcedure procedure = new HttpProcedure();

		fillProcedure(procedure, arguments);
		fillProcedure(procedure, cookies);
		fillProcedure(procedure, heads);

		procedure.id = id;
		procedure.results = results;
		if (body != null)
			procedure.body = new Expression(body.getPosition(), body.getExpressionString());
		if (times != null)
			procedure.times = new Expression(times.getPosition(), times.getExpressionString());
		procedure.testCase = testCase;
		if (url != null)
			procedure.url = new Expression(url.getPosition(), url.getExpressionString());
		return procedure;
	}

	private void fillProcedure(HttpProcedure procedure, Map<String, Expression> arguments) {
		for (Entry<String, Expression> entry : arguments.entrySet()) {
			Expression exp = entry.getValue();
			procedure.arguments.put(entry.getKey(), new Expression(exp.getPosition(), exp.getExpressionString()));
		}
	}

}
